import logging
import os
import random
import copy
import inspect
import StringIO
import traceback
import re
import sys
import types
import urllib
import cgi
import uuid
import base64
from webapp2_extras import sessions
from google.appengine.ext import db
from django.core.validators import validate_email
from django.core.validators import ValidationError
import djangoforms
from google.appengine.api import mail, memcache
import webapp2
from google.appengine.ext.db import GqlQuery
from settings import Settings
try:
  from django import newforms as forms
except ImportError:
  from django import forms
from models import Wombat, User, rchop, lchop, Account, WombatQuery, AmazonSESEmailMessage, EmailThrottlingCountClass
from wtforms.ext.appengine.db import model_form, form_model
from wtforms.ext.appengine.fields import ReferencePropertyField
from wtforms.form import Form
from wtforms.fields import PasswordField, HiddenField
from wtforms import validators
from settings import Settings
from __builtin__ import list as _list  # ???
#from main import template_environment
from google.appengine.ext import deferred
import threading
from google.appengine.api import search
import datetime
from webob.multidict import NestedMultiDict, UnicodeMultiDict
from yengine import log, controller, get_queue_target
from requirers import Requirer
import json
from yengine.db import EntityProblem
from keys import *
import itertools
from google.appengine.api import users
from boto.ses.exceptions import SESAddressBlacklistedError, SESAddressNotVerifiedError
import yengine.json

class WombatException(Exception):
  pass


class InvalidEntityException(WombatException):
  pass


class WombatSimpleRequestHandler(webapp2.RequestHandler):

  user_login_path = '/ulogin.html'
  user_logout_path = '/ulogout.html'

  def __init__(self, *args, **kwargs):
    super(WombatSimpleRequestHandler, self).__init__(*args, **kwargs)
    self.template_values = {}
    self.template_values['yreceipts'] = not bool('shopfeedback.it' in os.environ['HTTP_HOST'])

  def error(self, code, *args, **kwargs):
    if code in [400, 500]:
      try:
        subject = 'Error %u' % (code)
        sender_address = 'yReceipts Cloud<Customer.Service@yreceipts.com>'
        recipient = 'teamyr@yreceipts.com'
        body = u'Server Time   \n--------------------\n%s\n\n\n' % (unicode(datetime.datetime.now()))
        body += u'Environment   \n--------------------\n%s\n\n\n' % (unicode(os.environ))
        body += u'Query String  \n--------------------\n%s\n\n\n' % (unicode(self.request.query_string))
        body += u'Request Body  \n--------------------\n%s\n\n\n' % (self.request.body.decode('utf-8'))
        body += u'Traceback     \n--------------------\n%s' % (unicode(traceback.format_exc()))

        send_mail(sender_address, recipient, subject, body)
        logging.info('Problem notification sent')
        logging.info(body)
      except Exception as e:
        logging.critical('Could not send problem notification')
        logging.exception(e)

    super(WombatSimpleRequestHandler, self).error(code, *args, **kwargs)

  @classmethod
  def mapping(cls):
    return (cls.path, cls)


class WombatStaticRequestHandler(WombatSimpleRequestHandler):
  def get(self, path=None):
    import jinja2
    if not path:
      path = 'home.html'
    try:
      result = Settings.template_environment.get_template(path).render(self.template_values)
    except jinja2.exceptions.TemplateNotFound:
      self.error(404)
    else:
      self.response.out.write(result)


class WombatDefaultRequestHandler(WombatSimpleRequestHandler):

  def real_account(self, auth_key=None):
    if not auth_key and self.request:
      auth_key = self.request.GET.get('auth_key')
    try:
      auth = os.environ.get('HTTP_AUTHORIZATION', '')
      logging.debug('Auth = ' + auth)
      key = None
      if auth and auth.startswith('yRaccount'):
        credentials = auth[auth.find(' '):].strip()
        credentials = base64.b64decode(credentials)
        logging.debug('Auth string = ' + credentials)
        key, token = credentials.split(':')
      elif auth_key:
        credentials = base64.b64decode(auth_key)
        logging.debug('auth_key string = ' + credentials)
        key, token = credentials.split(':')
      if key:
        try:
          id = int(key)
          acc = Account.get_by_id(id)
        except:
          acc = Account.get_by_key_name(key)
        if token in acc.tokens:
          return acc
        else:
          return None
      else:
        logging.debug("Unable to find key from")
    except Exception as e:
      logging.warn('HTTP Authorization failed')
      logging.exception(e)
    logging.debug('No HTTP Authentication; probing internal methods')
    user = self.current_user
    if user:
      return user.get_active_account()
    return None

  def active_account(self, auth_key=None):
    #try:
    #  if 'active_account' in self.session:
    #    active = pickle.loads(self.session['active_account'])
    #    if active:
    #      return active
    #except Exception as e:
    #  logging.exception(e)
    real = active = self.real_account(auth_key)
    if not Settings.skip_login and real and real.is_default():
      app_user = users.get_current_user()
      if not (app_user and users.is_current_user_admin()):
        return None
    if hasattr(self, 'requested_account') and isinstance(self.requested_account, db.Model):
      active = self.override_account(real, self.requested_account)
    #try:
    #  self.session['active_account'] = pickle.dumps(active)
    #except Exception as e:
    #  logging.exception(e)
    return active

  @property
  def current_user(self):
    #this is actually a workaround for testing - not needed in production by any means
    if Settings.skip_login and 'yreceipts.com' not in os.environ.get('HTTP_HOST', 'yreceipts.com'):
      return User.get_by_key_name('test_user')
      #return User.get_or_insert('test_user', email='test@yreceipts.com', password='password')
    return self._current_user

  @webapp2.cached_property
  def _current_user(self):
    #this is actually a workaround for testing - not needed in production by any means
    #if Settings.skip_login and 'yreceipts.com' not in os.environ.get('HTTP_HOST', 'yreceipts.com'):
    #  return User.get_by_key_name('test_user')
    #  #return User.get_or_insert('test_user', email='test@yreceipts.com', password='password')
    session = self.session
    #try:
    #  if 'current_user' in self.session and self.session['current_user']:
    #    return pickle.loads(self.session['current_user'])
    #except Exception as e:
    #  logging.exception(e)
    if 'user_key' in session:
      try:
        user = db.get(session['user_key'])
    #    self.session['current_user'] = pickle.dumps(user)
        logging.debug('Returning user:' + repr(user))
        return user
      except:
        logging.warn('Invalid user key found in session: ' + repr(session['user_key']))
        return None
    return None

  @staticmethod
  def override_account(actual, requested):
    if requested and actual and requested.has_scope(actual):
      return requested
    return actual

  def dispatch(self):
    if Settings.skip_login and 'yreceipts.com' not in os.environ.get('HTTP_HOST', 'yreceipts.com'):
      if not User.get_by_key_name('test_user'):
        User(key_name='test_user', email='autotest@yreceipts.com', password='password').put()
    # Get a session store for this request.
    self.session_store = sessions.get_store(request=self.request)
    self.template_values['messages'] = self.session['messages'] \
      if 'messages' in self.session and self.session['messages'] else []
    self.session['messages'] = []
    self.template_values['current_user'] = self.current_user
    self.handle_account()
    try:
        # Dispatch the request.
        logging.info('Current user = %s' % repr(self.current_user))
        logging.info('Active account = %s' % repr(self.active_account()))
        logging.info('Real account = %s' % repr(self.real_account()))
        WombatSimpleRequestHandler.dispatch(self)
    finally:
        # Save all sessions.
        self.session_store.save_sessions(self.response)

  @webapp2.cached_property
  def session(self):
    # Returns a session using the default cookie key.
    return self.session_store.get_session()

  def handle_account(self):
    from config import WombatConfig
    try:
      if 'requested_account_key' in self.session and self.session['requested_account_key']:
        self.requested_account = db.get(self.session['requested_account_key'])
        logging.debug('Requested account = ' + str(self.requested_account))
      #elif self.current_user and self.current_user.last_used_account:
      #  self.session['requested_account_key'] = str(self.current_user.last_used_account.key())
      #  self.requested_account = self.current_user.last_used_account
    except Exception as e:
      logging.error('Unable to switch to the requested account')
      logging.exception(e)
    real = self.real_account()
    user = self.current_user
    logging.debug(real)
    if real and (real.is_default() or (real.service_account and user and user.type != 'user')):
      memcache_path = '/wombat/%s/available_accounts' % real.key()
      available_accounts = memcache.get(memcache_path)
      if available_accounts:
        logging.info('Loaded account list from memcache at %s' % memcache_path)
      else:
        logging.info('Loading account list from datastore')
        query = WombatQuery(Account, projection=['name', 'external_id', 'service_provider']).scope(real).filter('hidden', False).order('name')
        available_accounts = []
        for entity in query:
          available_accounts.append(
          {
            '__key__': entity.key(),
            'name': entity.name,
            'external_id': entity.external_id,
          })
        memcache.set(memcache_path, available_accounts)
      self.template_values['available_accounts'] = available_accounts
    self.template_values['active_account'] = self.active_account()
    self.template_values['real_account'] = real
    google_user = users.get_current_user()
    if google_user:
      self.template_values['google_user'] = google_user
      self.template_values['google_logout_url'] = users.create_logout_url(WombatRequestHandler.user_login_path)
      self.template_values['google_login_url'] = users.create_login_url(self.request.url)

  @controller
  def get(self):
    logging.info('Current user:' + str(self.current_user))
    api_token = self.request.get('api_token')
    active_account = self.active_account(api_token)
    logging.info('Active account:' + str(active_account))
    if not active_account:
      logging.info(self.request.url)
      self.session['login_referrer'] = self.request.url
      return False
    return self.check_user_auth_token()

  @controller
  def post(self):
    logging.info('Current user:' + str(self.current_user))
    api_token = self.request.get('api_token')
    active_account = self.active_account(api_token)
    logging.info('Active account:' + str(active_account))
    if not active_account:
      logging.info(self.request.url)
      self.session['login_referrer'] = self.request.url
      return False
    return self.check_user_auth_token()

  def check_user_auth_token(self):
    app_user = users.get_current_user()
    if app_user and users.is_current_user_admin():
      return True
    user = self.current_user
    has_valid_token = False
    if user and user.get_auth_token_cookie_name() in self.request.cookies:
      token = self.request.cookies[user.get_auth_token_cookie_name()]
      if user.is_auth_token_valid(token):
        has_valid_token = True
    has_datahub = user and user.account and user.account.datahub_index_name
    if (not Settings.skip_login and user and has_datahub and
        user.type not in ['datahub-write-only', 'datahub-till'] and not has_valid_token):
      self.redirect('/auth_code')
      return False
    return True

  @staticmethod
  def insert_into_mysql(entity):
    if '.' in os.environ['HTTP_HOST']:
      logging.debug('checking if entity has insert_into_MySQL')
      if hasattr(entity, 'insert_into_MySQL'):
        logging.info('queueing insert_into_MySQL')
        entity.queue_method_calls('insert_into_MySQL')
      logging.debug('checking if entity has make_search_index')
      if hasattr(entity, 'make_search_index'):
        logging.info('queueing make_search_index')
        entity.queue_method_calls('make_search_index')


local = threading.local()

def get_instance():
  if hasattr(local, 'WRH_instance'):
    return local.WRH_instance
  return None

def wombatted_iter_choices(self):
    wrh = local.WRH_instance

    placeholder = '<span style="color: gray;">%s</span>' % self.placeholder if self.placeholder else '<br />'

    if self.allow_blank:
      yield (u'__None', self.blank_text, self.data is None)

    from config import WombatConfig
    active_account = wrh.active_account()
    if not active_account:
      logging.warn('No account is active; returning nothing')
      return

    obj_scope = []
    if not hasattr(self._reference_class, 'scope') or not self._reference_class.scope:
      logging.info(str(self._reference_class.__name__)+' does not support scoping; fetching all records')
      queries = [self._reference_class.all()]
    else:
      logging.debug(str(self._reference_class.__name__)+' supports scoping; checking the active scope')
      queries = self._reference_class.get_reference_queries(self._model)
      if not hasattr(wrh, 'template_values') or not 'instance_name' in wrh.template_values or active_account.service_account:
        logging.debug('The active scope is '+str(active_account)+'; applying to the dropdown menu')
        for query in queries:
          query.scope(active_account)

      if hasattr(wrh, 'template_values') and 'instance_name' in wrh.template_values:# and not '.yreceipts' in os.environ['HTTP_HOST'].replace('www.', '')
        logging.debug('Looks like we are editing an existing entity')
        if not active_account.service_account:
          logging.debug('The active account is not a service account; further scoping needed')
          obj = wrh.template_values[wrh.template_values['instance_name']]
          obj_scope = obj.get_scope()[:]
          logging.debug('We are editing '+str(obj)+' ['+str(obj.key())+']; its scope is '+str(obj_scope))
          if not obj_scope or not WombatConfig.default_scope.key() in obj_scope:
            logging.info('This scope needs updating; refreshing the scope and reputting the entity')
            obj.refresh_scope()
            logging.info('The scope has been refreshed; about the call put() on the object')
            obj.put()
            logging.info('Put successfully')
            obj_scope = obj.get_scope()[:]
            logging.info('Updated scope is '+str(obj_scope))
          obj_scope.remove(WombatConfig.default_scope.key())
          logging.debug('Processed scope: '+str(obj_scope))
          if len(obj_scope) == 0:
            logging.warn(str(obj)+' ['+str(obj.key())+'] has the default scope only! This is not expected.')
            for query in queries:
              query.scope(active_account)
          elif len(obj_scope) == 1:
            logging.debug('Applying the scope '+str(obj_scope[0]))
            for query in queries:
              query.scope(obj_scope[0])
        else:
          logging.debug('What we have applied so far was a service account - no further action needed')
      else:
        logging.debug('Looks like we are creating a new item; no further scope will be applied')

    for query in queries:
      reference_class = query._model_class
      if hasattr(reference_class, 'ORDER') and isinstance(getattr(reference_class, 'ORDER'), _list) and len(getattr(reference_class, 'ORDER')) > 0:
        for column in getattr(reference_class, 'ORDER'):
          query.order(column)
      elif hasattr(reference_class, 'name') and isinstance(reference_class.name, db.Property):
        query.order('name')

    if self._model == self._reference_class and hasattr(self._model, 'apply_reference_property_query_filters'):
      self._model.apply_reference_property_query_filters(query)

    config = db.create_config(deadline=15, read_policy=db.EVENTUAL_CONSISTENCY)

    if len(obj_scope) > 1:
      logging.info('fetching by multiple scope')
      result = [query.fetch_by_scope(obj_scope) for query in queries]
    else:
      result = [query.run(config=config) for query in queries]

    for obj in list(itertools.chain(*result)):
        key = str(obj.key())
        if hasattr(obj, 'is_hidden') and obj.is_hidden():
          logging.debug('Omitting hidden item '+str(obj)+' ['+key+']')
          continue
        label = self.label_attr and getattr(obj, self.label_attr) or obj
        #label = str(obj)
        #logging.info('Displaying: '+str(obj)+' ['+str(key)+'] as '+str(label))
        yield (key, label, self.data and ( self.data.key( ) == obj.key() ) )
        pass

ReferencePropertyField.iter_choices = wombatted_iter_choices

class WombatException(Exception):
  pass

class Exception404(Exception):
  def __init__(self, value):
    self.value = value

  def __str__(self):
    return repr(self.value)

def set_default_request_template_values(request_handler):
  try:
    if 'message' in request_handler.session:
      message = request_handler.session['message']
      request_handler.session['message'] = ""
    else:
      message = False
    if 'consumer_key' in request_handler.session:
      logged_in = True
    else:
      logged_in = False
  except Exception as e:
    logging.exception(e)
    message = False
    logged_in = False
    request_handler.session = None
  if hasattr(request_handler,'template_values'):
    logging.debug("updating template values with session info")
    request_handler.template_values.update({ 'message' : message,
                      'session' : request_handler.session,
                      'logged_in' : logged_in,
                      'http_host' : 'http://' + os.environ['HTTP_HOST'],
                      'host' : os.environ['HTTP_HOST'],
                      'query_string' : request_handler.request.query_string})
  else:
    logging.debug("creating new tempplate values with session info")
    request_handler.template_values = { 'message' : message,
                      'session' : request_handler.session,
                      'logged_in' : logged_in,
                      'http_host' : 'http://' + os.environ['HTTP_HOST'],
                      'host' : os.environ['HTTP_HOST'],
                      'test_val': " ' < > ' ",
                      'query_string' : request_handler.request.query_string}


def _get_mod(modulePath):
    logging.debug('about to import ' + modulePath)
    aMod = None
    try:
        aMod = sys.modules[modulePath]
        if not isinstance(aMod, types.ModuleType):
            raise KeyError
    except KeyError,e:
      try:
        # The last [''] is very important!
        modulePath = lchop(modulePath, 'wombat.')
        logging.debug('tyring to import ' + modulePath)
        aMod = __import__(modulePath, globals(), locals(), [''])
        sys.modules[modulePath] = aMod
      except (KeyError, ImportError) as e:
        logging.debug('unable to import ' + modulePath + ' because ' +(str(e)))
      except Exception as e:
        logging.exception(e)
    return aMod

def _get_func(fullFuncName):
    """Retrieve a function object from a full dotted-package name."""

    # Parse out the path, module, and function
    try:
      lastDot = fullFuncName.rfind(u".")
      funcName = fullFuncName[lastDot + 1:]
      modPath = fullFuncName[:lastDot]

      if not funcName:
        logging.debug("no function name extension so returning")
        return None
      aMod = _get_mod(modPath)
      aFunc = getattr(aMod, funcName)

      # Assert that the function is a *callable* attribute.
      assert callable(aFunc), u"%s is not callable." % fullFuncName

      # Return a reference to the function itself,
      # not the results of the function.
      return aFunc
    except Exception as e:
      logging.debug('unable to find function object ' + fullFuncName)
      logging.debug(e)
      return None

def _get_class(fullClassName, parentClass=None):
    """Load a module and retrieve a class (NOT an instance).

    If the parentClass is supplied, className must be of parentClass
    or a subclass of parentClass (or None is returned).
    """
    aClass = _get_func(fullClassName)

    # Assert that the class is a subclass of parentClass.
    if parentClass is not None:
        if not issubclass(aClass, parentClass):
            raise TypeError(u"%s is not a subclass of %s" %
                            (fullClassName, parentClass))

    # Return a reference to the class itself, not an instantiated object.
    return aClass


class WombatActionPlugin(object):
  def __init__(self, request, response, entity, request_handler):
    self.request = request
    self.response = response
    self.entity = entity
    self.request_handler = request_handler


class WombatEntityHook(object):
  @log
  def __init__(self, entity):
    self.entity = entity

  def post(self):
    """Entity created."""
    pass

  def put(self):
    """Entity updated."""
    pass

  @staticmethod
  def handles_model(model_class):
    """State whether the given model class is handled by the hook."""
    return True

  @classmethod
  @log
  def call(cls, entity_key, action):
    logging.info('Calling hook %s.%s(%s)' % (cls.__name__, action, entity_key))
    entity = db.get(entity_key)
    hook = cls(entity)
    getattr(hook, action)()


class WombatLogEntityHook(WombatEntityHook):
  def put(self):
    logging.info('%s put' % repr(self.entity))

  def post(self):
    logging.info('%s posted' % repr(self.entity))

  @staticmethod
  def handles_model(model_class):
    return True


def hide_with_children(key, new_hide_value):
  import settings
  entity = db.get(key)
  if not entity:
    logging.info('entity with key ' + str(key) + ' has been deleted, wont hide')
    return
  entity.hidden = new_hide_value
  entity.put()
  if '.' in os.environ['HTTP_HOST']:
    entity.queue_method_calls('make_search_index')
  children = entity.get_children(True, True)
  children_deferred = False
  for cclass in children:
    for child in children[cclass]:
      deferred.defer(hide_with_children, child.key(), new_hide_value, _queue='wombat', _target=get_queue_target('request'))
      children_deferred = True
  for entity_to_hide in entity.get_entities_to_hide():
    deferred.defer(hide_with_children, entity_to_hide.key(), new_hide_value, _queue='wombat', _target=get_queue_target('request'))
    children_deferred = True
  logging.info('children_deferred = %s' % children_deferred)
  if not children_deferred:
    entity.clean_scope()
    for key in entity.get_scope(True, True):
      account = db.get(key)
      if not account.is_in_use():
        account.hidden = new_hide_value
        account.put()
        if '.' in os.environ['HTTP_HOST']:
          account.queue_method_calls('make_search_index')


def authenticate_user(request_function):
  def redirect(request_object):
    request_object.redirect(WombatRequestHandler.user_login_path)

  def check_credential(request_object, *args, **kwargs):
    session = request_object.session
    if Settings.skip_login:
      login_required = False
      logging.warn('Settings.skip_login == True')
    elif request_object.request.get('config') or request_object.request.get('property'):
      login_required = False
      logging.info('Fetching a property, login not required')
    else:
      login_required = request_object.request.path.startswith('/users/')
    if login_required:
      logging.info("login is required for " + request_object.request.path)
      #don't check it as too slow..
      auth_token = request_object.request.get('api_token')
      if auth_token:
          logging.info("found auth token " + auth_token)
      else:
          logging.info("no auth token found in url parameters")
      if request_object.active_account(auth_token):
        return request_function(request_object,*args,**kwargs)
      else:
       logging.info("adding login referrer to session" +request_object.request.path + "?" + request_object.request.query)
       session['login_referrer'] = request_object.request.path + "?" + request_object.request.query
       return redirect(request_object)
    else:
      logging.info("login not required for " + request_object.request.path)
      return request_function(request_object,*args,**kwargs)

  return check_credential

class WombatRequestHandler(WombatDefaultRequestHandler):

  search_path = '/search'
  public_access = False

  _instance = None
  def __new__(cls, *args, **kwargs):
    local.WRH_instance = super(WombatRequestHandler, cls).__new__(cls, *args, **kwargs)
    return local.WRH_instance

  def __init__(self, *args, **kwargs):
    super(WombatRequestHandler, self).__init__(*args, **kwargs)
    self.posted_entity = None



  def handle_exception(self, exception, debug_mode):
    try:
      out_file = StringIO.StringIO()
      traceback.print_exc(10,out_file)
      logging.error(out_file.getvalue())
      if not debug_mode:
        try:
          session = self.session
          session['message'] = "Oops! That wasn't meant to happen. We've recorded the problem and will look at it as soon as possible."
          logging.exception("We had an exception %s" + str(exception))
        except:
          logging.exception("we had another exception")
        self.redirect('/home.html')
      else:
        logging.exception("We had an exception %s" + str(exception))
        WombatSimpleRequestHandler.handle_exception(self, exception, debug_mode)
    except:
      pass



  @staticmethod
  def get_module_name_from_path(path):
    '''
      /receipts/receipt_feedback_form ==> receipts.models
    '''
    path_parts = path.split('/')
    #drop the last element
    path_parts = path_parts[0:-1]
    module_name = ".".join(path_parts) + '.models'
    module_name = module_name.lstrip(".")
    return module_name

  @staticmethod
  def get_handler_module_name_from_path(path):
    '''
      /wombat/user ==> wombat.user.views
    '''
    path_parts = path.split('/')
    #drop the last element
    path_parts = path_parts[0:-1]
    module_name = ".".join(path_parts) + '.views'
    module_name = module_name.lstrip(".")
    return module_name

  @staticmethod
  def get_handler_class_name_from_path(path):
    '''
      /wombat/user ==> wombat.views.UserHandler
    '''
    path = path.rstrip("/")
    module_name = WombatRequestHandler.get_handler_module_name_from_path(path)
    class_name = path.split('/')[-1]
    class_name = WombatRequestHandler.path_name_to_class_name(class_name)
    if class_name:
      class_name = module_name + "." + class_name
      if not class_name.endswith('Handler'):
        class_name = class_name +'Handler'
        logging.debug(" potential handler name from " + path + " into " + class_name)
      return class_name
    else:
      logging.debug(path + " couldnt be converted a handler name")
      return ""

  @staticmethod
  def get_form_class_name_from_path(path):
    '''
      /receipts/receipt_feedback_form ==> receipts.models.ReceiptFeedbackForm
      /businesses/pos_device ==> businesses.models.PosDeviceForm
      /businesses/business_location/ ==> businesses.models.BusinessLocation
    '''
    path = path.rstrip("/")
    module_name = WombatRequestHandler.get_module_name_from_path(path)
    class_name = path.split('/')[-1]
    class_name = WombatRequestHandler.path_name_to_class_name(class_name)
    if class_name:
      class_name = module_name + "." + class_name
      if not class_name.endswith('Form'):
        class_name = class_name +'Form'
        logging.debug(" potential form name from " + path + " into " + class_name)
      return class_name
    else:
      logging.debug(path + " couldnt be converted into a form name")
      return ""

  @staticmethod
  def get_base_form_class_name_from_path(path):
    '''
      /receipts/receipt_feedback_form ==> receipts.models.BaseReceiptFeedbackForm
      /businesses/pos_device ==> businesses.models.BasePosDeviceForm
    '''
    path = path.rstrip("/")
    module_name = WombatRequestHandler.get_module_name_from_path(path)
    class_name = path.split('/')[-1]
    class_name = WombatRequestHandler.path_name_to_class_name(class_name)
    if class_name:
      class_name = module_name + "." + 'Base' + class_name
      if not class_name.endswith('Form'):
        class_name = class_name +'Form'
        logging.debug(" potential form name from " + path + " into " + class_name)
      return class_name
    else:
      logging.debug(path + " couldnt be converted into a base form name")
      return ""

  @staticmethod
  def get_full_class_name_from_path(path):
    '''
      /receipts/receipt_feedback_form ==> receipts.models.ReceiptFeedback
    '''
    class_name = WombatRequestHandler.get_form_class_name_from_path(path)
    if class_name:
      class_name = rchop(class_name,"Form")
      logging.debug(" potential class name from " + path + " into " + class_name)
      return class_name
    else:
      logging.debug('returning none for full class name from path ' + path)
      return ""

  @classmethod
  def get_class_from_path(cls, path):
    class_name = cls.get_full_class_name_from_path(path)
    try:
       class_object = _get_class(class_name)
       return class_object
    except Exception as e:
      logging.debug("couldn't get class from path " + path)
      return None

  @staticmethod
  def get_full_class_name_from_query_and_path(query_parameter,path):
    '''
      receipt_key, /receipts/receipt_feedback_form ==> receipts.models.Receipt
    '''
    module_name = WombatRequestHandler.get_module_name_from_path(path)
    class_name = "".join([word[0].upper() + word[1:] for word in query_parameter.split('_')])
    class_name = rchop(class_name,"Key")
    return module_name + "." + class_name


  @staticmethod
  def path_name_to_class_name(path):
    '''
      receipt_feedback ==> ReceiptFeedback
      /blah/blah/receipt_feedback ==> ReceiptFeedback
      /businesses/business_location ==> business_location
    '''
    end_of_path = path.split('/')[-1]
    if len(end_of_path) > 0:
      class_name = "".join([word[0][0].capitalize() + word[1:] for word in end_of_path.split('_')])
      logging.debug("path name to class name returning " + class_name)
      return class_name
    else:
      logging.debug('path couldnt be converted into class name ' + path)

  def get_template_from_url(self, path, clear = True):
    if path == '/':
      template_path = 'home.html'
      template = Settings.template_environment.get_template(template_path)
      return template
    if path in ['/user', '/account']:
      path = '/wombat' + path
    #template_path = os.path.dirname(__file__)
    #template_path = rchop(template_path,'wombat')
    template_path =  path.lstrip('/').lstrip('\\')
    #checck if it's looking for a list
    model_class = _get_class(self.get_full_class_name_from_path(path))
    if path.endswith('/'):
      logging.debug(path + ' ends with / so looking for a list template')
      template_path = template_path.rstrip('/')
      template_path += '_list'
    if  not '.' in template_path:
      template_path += '.html'
      logging.debug("added html to template path now " + template_path)
    if not 'instance_name' in self.template_values or not model_class == Account:
      try:
        template = Settings.template_environment.get_template(template_path)
        logging.debug("path exists " + template_path)
        return template
      except Exception as e:
        logging.debug('path doesnt exist ' + template_path)
    logging.debug("Checcked for path on " + template_path)
    #see if the template path converts into a model.. if so return the default form.
    try:
      if model_class:
        #model exists, now we need to see if it's a list
        if path.endswith('/'):
          template_path = 'base_list.html'
        #elif clear:
        #  template_path = 'base_form_clear.html'
        else:
          template_path = 'base_form_chooser.html'
        logging.debug('*** using template:' + template_path)
        template = Settings.template_environment.get_template(template_path)
        return template
      else:
        logging.debug("won't default the path to the default form")
      logging.warn("the path " + path + " does not exist")
    except:
      logging.debug("couldn't find a model class matching " + path  )
    logging.debug("Couldn't find a template matching " + path + " reuturning none")
    return None

  @classmethod
  def put_query_models_into_template_values(cls,path,query_string,template_values,post_data=None):
    '''
      /receipts?key=abcde&consumer_key=abcde ==> template_values['instance_name' => Receipt, 'Consumer' => Consumer]
    '''
    themodel = cls.get_class_from_path(path)
    logging.debug("puttling query models into template values")
    self_instance = None
    if query_string:
      key_given = False
      nothing_found = True
      parts = cgi.parse_qsl(query_string)
      params = {}
      for part in parts:
        try:
          (key,value) = part
          if key and value:
            params[key]=value
        except Exception as e:
          logging.error('error changing params into dict ')
          logging.exception(e)
      for key,value in params.items():
        try:
          if key == 'index':
            nothing_found = False
            model_name = WombatRequestHandler.get_full_class_name_from_path(path)
            cur_class = _get_class(model_name)
            index_name = value
            index_value = params[value]
            self_instance = cur_class.all().filter(index_name +' = ',index_value).get()
            if self_instance:
              instance_name = Wombat.class_name_to_path_name(model_name)
              template_values[instance_name] = self_instance
              template_values['instance_name'] = instance_name
              template_values['model_name'] = model_name
              template_values['key'] = self_instance.key()
              logging.debug("added an index self instance " +instance_name + " = " +str(self_instance))
            else:
              logging.info('key ' + value + ' wasnt found, not setting template values ')
              raise Exception404('index ' + value + ' wasnt found')
          elif key == 'key':
            key_given = True
            model_name = WombatRequestHandler.get_full_class_name_from_path(path)
            cur_class = _get_class(model_name)
            logging.debug("found model " + model_name)
            try:
              self_instance = cur_class.get(value)
            except db.BadKeyError:
              pass
            except Exception as e:
              EntityProblem.add(value, 'WombatHandler.put_query_models_into_template_values failed')
              raise InvalidEntityException(e)
            #if not self_instance:
            #  template_values['error_encountered'] = 404
            #  return template_values
            if self_instance:
              nothing_found = False
              instance_name = Wombat.class_name_to_path_name(model_name)
              template_values[instance_name] = self_instance
              template_values['instance_name'] = instance_name
              template_values['model_name'] = model_name
              template_values['key'] = self_instance.key()
              logging.debug("added self instance " +instance_name + " = " +str(self_instance))
            else:
              logging.info('key ' + value + ' wasnt found, not setting template values ')
              #raise Exception404('key ' + value + ' wasnt found')
          elif key.endswith('_key') and not hasattr(themodel, key):
            nothing_found = False
            model_name = WombatRequestHandler.get_full_class_name_from_query_and_path(key, path)
            logging.debug("found model " + model_name)
            cur_class = _get_class(model_name)
            if cur_class:
              instance = cur_class.get(Wombat.yRKey(value))
              instance_name = Wombat.class_name_to_path_name(model_name)
              template_values[instance_name] = instance
            else:
              logging.debug('instance found for ' + model_name + ' with key ' + value)
              instance_name=None
              instance=None
            if instance_name:
              if 'reference_models' not in template_values:
                logging.debug('setting up a new reference model with ' + instance_name)
                template_values['reference_models'] = [instance_name]
              else:
                logging.debug('adding another reference model with ' + instance_name)
                template_values['reference_models'] = template_values['reference_models'].append(instance_name)
              if instance_name and instance:
                logging.debug("added model instance " +instance_name + " = " +unicode(instance))
          else:
            if key in template_values:
              logging.warn(key + " already in template values, not adding againg")
            else:
              logging.debug("setting " + key + " to " + value)
              template_values[key] = value
        except Exception as e:
          raise
          logging.exception(e)
      if nothing_found and len(params) > 0 and not path.endswith('/'):
        model_name = WombatRequestHandler.get_full_class_name_from_path(path)
        cur_class = _get_class(model_name)
        if not hasattr(cur_class, 'find'):
          return template_values
        legal_args = inspect.getargspec(getattr(cur_class, 'find'))[0]
        for name in params.keys():
          if not name in legal_args:
            del params[name]
          else:
            params[name] = urllib.unquote_plus(params[name])
        logging.debug('About to call Model().find()')
        try:
          self_instance = cur_class.find(**params)
          if not self_instance:
            template_values['error_encountered'] = 404
            return template_values
        except Exception as e:
          logging.warn('Model().find() call failed')
          logging.exception(e)
          #template_values['error_encountered'] = 400
          return template_values
        #if not self_instance:
        #  template_values['error_encountered'] = 404
        #  return template_values
        instance_name = Wombat.class_name_to_path_name(model_name)
        template_values[instance_name] = self_instance
        template_values['instance_name'] = instance_name
        template_values['model_name'] = model_name
        template_values['key'] = self_instance.key()
    else:
      logging.debug("no query string so not adding any models from there")
    return template_values

  @staticmethod
  def get_handler_from_path(path):
    if path in [WombatRequestHandler.user_login_path, WombatRequestHandler.user_logout_path]:
      return None
    handler_class_name = WombatRequestHandler.get_handler_class_name_from_path(path)
    try:
      handler_class = _get_class(handler_class_name)
      return handler_class
    except Exception as e:
      logging.info(path + " doesn't convert to " + handler_class_name + " add this class to override ")
      logging.info('Unable to get ' + path + ' because ' + str(e))
      logging.info(e)
    return None


  def get_form_from_path(self,path,query_string,template_values,post_data=None,force_exclusions=False, light=False):
    '''
       /receipts/receipt_feedback_form ==> template_values['receipt_feedback_form' : ReceiptFeedbackForm]
       /businesses/pos_device ==> template_values['pos_device_form' : 'PosDeviceForm]
    '''
    #Todo - create from if none found
    if 'instance_name' in template_values:
      logging.debug('Adding a lot of stuff')
      self_instance = template_values[template_values['instance_name']]
      template_values['entity'] = self_instance
      problem = False
      if not light:
        try:
          template_values['ancestors'] = self_instance.get_main_ancestors(True)
        except:
          EntityProblem.add(self_instance, 'entity.get_main_ancestors(True) failed')
          problem = True
        try:
          template_values['parents'] = self_instance.get_parents()
        except:
          EntityProblem.add(self_instance, 'entity.get_parents() failed')
          problem = True
        try:
          template_values['children'] = self_instance.get_children()
        except:
          EntityProblem.add(self_instance, 'entity.get_children() failed')
          problem = True
        try:
          template_values['possible_children'] = self_instance.get_possible_children()
        except:
          EntityProblem.add(self_instance, 'entity.get_possible_children() failed')
          problem = True
        try:
          template_values['actions'] = dict((k, v) for k, v in self_instance.get_actions().items() if not v['hidden'])
        except:
          EntityProblem.add(self_instance, 'entity.get_actions() failed')
          problem = True
        try:
          template_values['extra_tabs'] = self_instance.extra_tabs
        except:
          EntityProblem.add(self_instance, 'entity.extra_tabs() failed')
          problem = True
        if problem:
          try:
            if self.template_values['form_exception']:
              self.template_values['form_exception'] += '<br />'
          except KeyError:
            self.template_values['form_exception'] = ''
          self.template_values['form_exception'] += 'We encountered a problem and could not load some features of this page. The support team have been notified and will look into it soon. You need take no action, but please feel free to contact us should you have any questions. We are sorry about this issue.'
    else:
      self_instance = None
      #if self.active_account().key() != self.real_account().key():
      #  template_values['add_as_accounts'] = Account.all().scope(self.real_account()).order('name').fetch(1000)
      if self.active_account() and self.active_account().is_default():
        template_values['add_as_accounts'] = WombatQuery(Account, projection=['name']).filter('hidden =', False).order('name')
    form_class_name = WombatRequestHandler.get_form_class_name_from_path(path)
    model_class_name = WombatRequestHandler.get_full_class_name_from_path(path)
    base_form_class_name = WombatRequestHandler.get_base_form_class_name_from_path(path)
    model_class = None
    try:
      logging.debug('get form is looking for ' + model_class_name)
      model_class = _get_class(model_class_name)
    except:
      logging.debug("Unable to find " + model_class_name)
    form_class = None
    if ('instance_name' not in template_values and (not self.current_user or self.current_user.type == 'user' or not self.current_user.account)) or model_class != Account:
    #if not 'instance_name' in template_values or not model_class == Account:
      try:
        form_class = _get_class(form_class_name)
      except:
        logging.debug("Unable to find " + str(form_class_name))
    exclude = []
    base_form_class = Form
    try:
      base_form_class = _get_class(base_form_class_name)
      logging.debug(base_form_class_name + ' was found, will use as the base')
      base_form_class = Form
    except:
      logging.info(base_form_class_name + ' could not be found')
    if not form_class:
      if model_class:
        exclude = model_class.properties().keys()
        form_name = form_class_name.split('.')[-1]
        logging.debug("generating a new form class with name " + form_name)
        #MetaClass = type("Meta", (), {"model": model_class,"exclude":['scope'] })
        #form_class = type(form_name, (WombatForm,), {"Meta": MetaClass})
        if not self_instance and 'new' in model_class.FIELDS_VISIBILITY:
          exclude = [x for x in exclude if x not in model_class.FIELDS_VISIBILITY['new']]
        elif not (self.real_account() and self.real_account().is_default()) and self.current_user and self.current_user.type in model_class.FIELDS_VISIBILITY:
          exclude = [x for x in exclude if x not in model_class.FIELDS_VISIBILITY[self.current_user.type]]
        elif self.real_account() and self.real_account().is_default():
          exclude = []
        elif self.current_user and self.current_user.type == 'admin':
          exclude = model_class.exclude[:]
        elif 'guest' in model_class.FIELDS_VISIBILITY:
          exclude = [x for x in exclude if x not in model_class.FIELDS_VISIBILITY['guest']]
        #else:
        #  exclude.extend(model_class.strong_exclude)
        #  exclude.extend(model_class.exclude)
        exclude += model_class.strong_exclude
        if hasattr(self, 'custom_post_data') and self.custom_post_data:
          post_data = self.request.POST
          for key in self.custom_post_data.keys():
            post_data[key] = self.custom_post_data[key]
        if post_data and not force_exclusions:
          for key in post_data.keys():
            if key in exclude:
              exclude.remove(key)
        exclude.extend(['scope', 'added_on', 'hidden', 'modified_on'])
        if hasattr(model_class, 'field_args'):
          field_args = model_class.field_args
        else:
          field_args = {}
        exclude, _ = self.modify_field_visibility(exclude)
        #form is created here..
        form_class = model_form(model_class, base_class=base_form_class, exclude=exclude, field_args=field_args)
        if hasattr(model_class, 'filter_form_class'):
          model_class.filter_form_class(form_class)
        new_props = {}
        for prop in Wombat.props(form_class).keys():
          if prop.lower() in ['password', '_password']:
            if not self_instance:
              new_props[prop] = PasswordField(validators=[validators.Length(1, message='Password cannot be empty.')])
            new_props['confirm_' + prop] = PasswordField(validators=[validators.EqualTo(prop, message='Passwords did not match.')])
        for prop in new_props.keys():
          setattr(form_class, prop, new_props[prop])
        if hasattr(self,'extra_form_fields'):
          for field in self.extra_form_fields:
            setattr(form_class,field['name'],field['value'])
        if self_instance:
          setattr(form_class,'_self',HiddenField(label='',validators=None,default=str(self_instance.key())))
        if hasattr(model_class,'extra_form_fields'):
          for field in model_class.extra_form_fields:
            setattr(form_class,field['name'],field['value'])
      else:
        logging.debug(' mo model found corresponding to ' + str(model_class_name) + " so not generating a class " + str(form_class_name))
        return template_values
    else:
      logging.debug("found form class in code " + form_class_name)
    if query_string:
      template_values['form_action']=path + "?" + query_string
    else:
      template_values['form_action']=path
    logging.debug("set form actin path to " + template_values['form_action'])
    logging.debug('exclude = ' + str(exclude))
    form_data = form_class(formdata=post_data,obj=self_instance,model=model_class,exclude=exclude)
    #form_data = form_class(data=post_data)
    template_values['form'] = form_data

    return template_values

  def get_list_from_path(self, path, template_values, limit=10, offset=0, property=None, format=None, display_headers=True, url_format=None):
    '''
      /businesses/pos_device/ ==> template_values{ entity_list :[ businesses.models.PosDevice1,businesses.models.PosDevice2 .. ]}
    '''
    if not self.active_account():
      template_values['entity_list'] = []
      return template_values

    entity_class = _get_class(WombatRequestHandler.get_full_class_name_from_path(path))
    template_values['model_name'] = entity_class.get_user_friendly_plural_class_name()
    get_entity_list = lambda current_header: []
    if entity_class.scope or self.active_account().is_default():
      query = entity_class.all(projection=entity_class.get_list_projection()).filter('hidden =', False)
      if entity_class.scope:
        query.scope(self.active_account())

      if hasattr(entity_class, 'ORDER') and isinstance(getattr(entity_class, 'ORDER'), list) and len(getattr(entity_class, 'ORDER')) > 0:
        for column in getattr(entity_class, 'ORDER'):
          query.order(column)
      elif hasattr(entity_class, 'name') and isinstance(entity_class.name, db.Property):
        query.order('name')

      config = config = db.create_config(deadline=3600, read_policy=db.EVENTUAL_CONSISTENCY)

      current_header = None
      if display_headers and offset:
        try:
          previous_entity = copy.deepcopy(query).get(offset=offset - 1, config=config)
          if previous_entity:
            current_header = previous_entity.header
        except Exception as e:
          logging.exception(e)
          current_header = None

      def get_entity_list(current_header):
        for r in query.run(limit=limit, offset=offset, config=config):
          if display_headers and r.header != current_header:
            yield r.header
            current_header = r.header
          #logging.info('yielding %s' % r)
          yield r
    template_values['entity_list'] = get_entity_list(current_header)
    if property:
      template_values['_title'] = lambda a: a.get_property(property)
    elif format:
      template_values['_title'] = lambda a: format % a
    else:
      template_values['_title'] = str
    if url_format:
      template_values['_url'] = lambda a: url_format % a
    else:
      template_values['_url'] = lambda a: '%(uri)s' % a

    logging.debug("added a list of objects of type  " + str(entity_class.__name__))
    return template_values

  @authenticate_user
  def head(self):
    pass

  def send_new_password(self, email):
    message = "Hello,\n\nSomeone has just used the forgotten password function on http://www.yreceipts.com and entered this email address. If it wasn't you, please reply to this message and describe the situation.\n\n"
    user = User.all().filter('email =', email).get()
    if not user:
      message += "Unfortunately, we do not have this email address in our database."
    else:
      password = str(uuid.uuid4())
      user.password = password
      user.put()
      user.uses_autogenerated_password = True
      user.put()
      message += "Your new password is: " + password
    message += "\n\nThank you for using our service,\nThe yReceipts Team"
    sender = "yReceipts Passwords Service <Customer.Service@yReceipts.com>"
    reply_to = "yReceipts <GetInTouch@yReceipts.com>"
    recipients = email
    subject = "Your new password"
    send_mail(sender, recipients, subject, message, reply_to=reply_to, bcc="teamyr@yreceipts.com")

  @staticmethod
  def get_entity_parents(entity):
    parents = []
    properties = entity.properties()
    for property_name in properties.keys():
      if isinstance(properties[property_name], db.ReferenceProperty):
        parent = getattr(entity, property_name)
        if not parent or hasattr(parent, 'is_hidden') and parent.is_hidden():
          continue
        parents.append(parent)
    return parents

  @log
  def get_search(self):
    query = self.request.get('query')
    logging.info('Search query = ' + str(query))
    if not query:
      self.response.out.write('Empty search query.')
    if not 'distance' in query:
      query = query.replace(',', ' ')
    try:
      if not ' ' in query:
        entity = None
        try:
          key = db.Key(query)
          logging.info(key)
          if key:
            entity = db.get(key)
            logging.info(entity)
        except Exception as e:
          logging.debug(e)

        if not entity:
          try:
            from users.businesses.models import PosDevice
            entity = PosDevice.find(query)
          except Exception as e:
            logging.debug(e)

        if entity and (not hasattr(entity, 'scope') or entity.has_scope(self.active_account())):
          self.template_values['search_entity'] = entity
          self.template_values['search_entity_parents'] = self.get_entity_parents(entity)
          logging.debug(entity)
          logging.debug(self.template_values['search_entity_parents'])
    except Exception as e:
      logging.exception(e)

    found_entities = {}
    try:
      index = search.Index(name='/wombat')
      results = index.search('scope = %s AND (%s)' % (self.active_account().key(), query))
      for result in results:
        entity = {}
        for field in result.fields:
          if field.name.endswith('_KEYS'):
            entity[field.name[:-5]] = [e.get_as_json_dict() for e in db.get(field.value.split(' '))]
          entity[field.name] = field.value
        if not str(self.active_account().key()) in entity['scope']:
          continue
        if not entity['plural_kind'] in found_entities:
          found_entities[entity['plural_kind']] = []
        found_entities[entity['plural_kind']].append(entity)
      self.template_values['search_found_kinds'] = sorted(found_entities.keys())
      self.template_values['search_found_entities'] = found_entities
    except Exception as e:
      logging.exception(e)

    if self.request.get('format') == 'json':
      json_dict = yengine.json.make_data_json_friendly(self.template_values['search_found_entities'])
      as_json = json.dumps(json_dict, indent=4)
      self.response.out.write(as_json)
    else:
      template = Settings.template_environment.get_template('search_results.html')
      self.response.out.write(template.render(self.template_values))

  def request_account(self, acc_key):
    logging.debug(acc_key)
    acc_key = str(acc_key)
    self.session['requested_account_key'] = acc_key
    user = self.current_user
    if user:
      logging.debug('updating_user')
      user.last_used_account = db.Key(acc_key)
      user.put()
    logging.debug(acc_key)
    if 'active_account' in self.session and self.session['active_account']:
      del self.session['active_account']

  @authenticate_user
  @controller
  def get(self,action=None):
    '''
       some examples of what this does
       /path/view and template?model_key=askdjffd
       /receipts/receipt_feedback_form
       /businesses/pos_device?property=config&key=asdfsf ==> config property of pos_device with relevant key
       businesses/pos_device?key=asfdsfs ==> form with the pos device filled in
       /businesses/business_location/ ==> paginated list of business locations
    '''
    logging.info(self.request.headers)
    if 'Authorization' in self.request.headers and self.request.headers['Authorization']:
      os.environ['HTTP_AUTHORIZATION'] = self.request.headers['Authorization']
    from config import WombatConfig
    try:
      active_path = self.request.path
      logging.info('active_path: ' + str(active_path))
      if active_path.startswith('/wombat/request_account'):
        logging.info('account change requested')
        self.request_account(self.request.get('account_key'))
        self.response.out.write('requested account set')
        return
      #ths is needed for compatibility with the old pos config stuff
      if active_path.startswith("/businesses/pos_device"):
        logging.warn("changing path of: " + active_path)
        active_path = "/users" + active_path

      if active_path in ['/user', '/account']:
        self.redirect('/new_device.html#chat')
        return

  #   must consider receipt feedback handler for login
      session = self.session
      if active_path == self.user_logout_path:
          #self.current_user.log_out()
          del session['user_key']
          session_keys = session.keys()[:]
          for key in session_keys:
            del session[key]
          session = {}
          self.redirect(WombatConfig.after_logout_path)
          return
      if not self.check_user_auth_token():
        return False
      if active_path == self.search_path:
        self.get_search()
        return
      app_user = users.get_current_user()
      real = self.real_account()
      if not Settings.skip_login and real and real.is_default() and not (app_user and users.is_current_user_admin()) and not self.public_access:
        self.redirect(users.create_login_url(self.request.url))
        return
      user = self.current_user
      user_key = str(user.key()) if user else ''
      if (self.current_user and active_path.count('/') > 1):
        if (self.current_user.type in ['datahub', 'datahub-till'] and
            ('/wombat/user' not in active_path or
             self.request.get('key') != user_key)):
              self.redirect('/datahub')
              return
        if self.current_user.type == 'datahub-write-only':
          self.redirect('/datahub#/customer')
          return
      if active_path == self.user_login_path:
        if self.current_user:
          self.redirect(WombatConfig.after_login_path)
          return
        if 'user_key' in session:
          del session['user_key']
        if 'active_account' in session:
          del session['active_account']
        if 'current_user' in session:
          del session['current_user']
        session = {}
        current_params = {}
        for arg in self.request.arguments():
          current_params[arg] = self.request.get(arg)
        self.session['login_arguments'] = current_params
        logging.debug('getting a login form')
        self.template_values.update({'form' : LoginForm(self.request.GET),
                                'form_action' : active_path})
        if self.request.query_string:
          self.template_values['form_action'] += self.make_query_string(self.request.GET, delete=['email', 'action'])
        template_path = 'ulogin.html'
        action = self.request.get('action')
        if action == 'send_password':
          try:
            self.send_new_password(self.request.get('email'))
            self.template_values['form_message'] = "We have emailed you a new password. Please check your inbox."
          except Exception as e:
            logging.exception(e)
            self.template_values['form_exception'] = 'We could not generate a new password for you. Please try again later.<br />Please email us on <a href="getintouch@yreceipts.com">GetInTouch@yReceipts.com</a> if the problem persists.'
        template = Settings.template_environment.get_template(template_path)
        self.response.out.write(template.render(self.template_values))
        return
      set_default_request_template_values(self)
      template = None
      try:
        self.template_values = WombatRequestHandler.put_query_models_into_template_values(active_path,self.request.query_string, self.template_values)
      except InvalidEntityException as e:
        template = Settings.template_environment.get_template('error.html')
        self.template_values['error'] = 'We encountered a problem and could not load this entity. The support team have been notified and will look into it soon. You need take no action, but please feel free to contact us should you have any questions. We are sorry about this issue.'
      if not template:
        template = self.get_template_from_url(active_path, not bool(self.request.get('key')))
      if 'error_encountered' in self.template_values:
        logging.info('Error: '+str(self.template_values['error_encountered']))
        self.error(self.template_values['error_encountered'])
        return
      data = None
      if not 'instance_name' in self.template_values:
        data = self.request.GET
      self.template_values = self.get_form_from_path(active_path,self.request.query_string, self.template_values, data, light=bool(self.request.get('action')))
      self.template_values['base_request'] = active_path + self.request.query_string
      if active_path != "/" and active_path.endswith("/"):
        logging.debug("getting a list of objectes because path ends in / ")
        params = {'limit': 100}
        if self.request.get('limit') and int(self.request.get('limit')) > 0:
          params['limit'] = int(self.request.get('limit'))
        if self.request.get('offset') and int(self.request.get('offset')) > 0:
          params['offset'] = int(self.request.get('offset'))
        property = self.request.get('property')
        if property:
          params['property'] = property
        format = self.request.get('format')
        if format:
          params['format'] = format
        url_format = self.request.get('url_format')
        if url_format:
          params['url_format'] = url_format
        display_headers = self.request.get('display_headers')
        if display_headers:
          params['display_headers'] = display_headers.lower() != 'false' and bool(display_headers)
        if self.request.get('ajax') and self.request.get('ajax').lower() == 'true':
          self.template_values['ajax'] = True
        self.template_values = self.get_list_from_path(active_path, self.template_values, **params)
      if self.request.get('property') and not active_path.endswith("/"):
        property_name = self.request.get('property')
        property_found = False
        if 'instance_name' in self.template_values:
          instance_name = self.template_values['instance_name']
          object = self.template_values[instance_name]
          if property_name == '__key__':
            property_found = True
            self.response.out.write(object.key())
          elif hasattr(object, property_name):
            property_found = True
            self.response.out.write(getattr(object,property_name))
          elif '.' in property_name:
            name_parts = property_name.split('.')
            for i in range(0, len(name_parts)):
              if i == len(name_parts)-1:
                if hasattr(object, name_parts[i]):
                  property_found = True
                  self.response.out.write(getattr(object,name_parts[i]))
              else:
                if hasattr(object, name_parts[i]):
                  object = getattr(object, name_parts[i])
                  logging.debug('using ' + repr(object))
                else:
                  break
          if not property_found:
            logging.info("no property found " + property_name + " in " + instance_name)
            self.response.set_status(404)
        else:
          logging.error("property set " + property_name + " but no matching model found for " + active_path)
          self.response.set_status(404)
      elif self.request.get('action'):
        entity = self.template_values['entity']
        #logging.debug('session: ' + str(self.session))
        #logging.info('scope property = ' + str(entity.__class__.scope))
        #logging.info(self.active_account().is_default())
        if not self.active_account() or not entity.has_scope(self.active_account()) or (not entity.__class__.scope and not self.active_account().is_default()):
          logging.info(self.active_account())
          logging.info('Access denied')
          self.error(403)
          return
        action = self.request.get('action')
        if not action in entity.get_actions():
          self.error(404)
          return
        entity.get_actions()[action]['class'](self.request, self.response, entity, self).get()
      elif not template:
        self.redirect('/home.html')
      else:
        if 'entity' in self.template_values:
          entity = self.template_values['entity']
          #logging.info('session: ' + str(self.session))
          if not self.real_account():
            logging.debug('guest user')
            self.error(403)
            return
          if not entity.__class__.scope and not self.active_account().is_default():
            logging.info(str(entity) + ' entity does not support scoping and the active account is not the default scope')
            self.error(403)
            return
          if entity.__class__.scope and not entity.has_scope(self.active_account()):
            logging.info(str(entity) + ' entity does not have the same scope as the active account')
            self.error(403)
            return
        self.modify_data()
        #template = Settings.template_environment.get_template(template_path)
        @log
        def render():
          self.response.out.write(template.render(self.template_values))
        render()
        #self.response.out.write(template.render(template_path, self.template_values))
    except Exception404:
      self.error(404)

  '''
  This method is in case an inheriting class want's to modify data before it is rendered
  '''
  def modify_data(self):
    pass

  def modify_field_visibility(self, exclude=[], include=[]):
    return exclude, include


  @staticmethod
  def set_complex_form_arguments(args,request,entity):
    for key in args:
      if key:
        if '.' in key:
          try:
            (object,property) = key.split(".",1)
          except Exception as e:
            logging.error(key + " caused exception while splittin for complex arg ")
            logging.exception(e)
            return
          if hasattr(entity, object):
            #try to get it from already existing objects..
            ref_object = getattr(entity, object)
            if ref_object:
              if hasattr(ref_object, property):
                #from here we'll need the value regardless
                value = request.get(key)
                if hasattr(ref_object, 'unique_properties') and property in ref_object.unique_properties:
                  logging.debug(str(ref_object) + " " + property + " is a unique property ")
                  existing_obj = ref_object.__class__
                  logging.info("found " + str(existing_obj))
                  existing_obj = existing_obj.all().filter(property + ' = ',value).get()
                  if existing_obj:
                    logging.info(value + " had an existing object was found with the unique property, using that instead")
                    setattr(entity, object, existing_obj)
                    entity.put()
                    return
                  else:
                    logging.debug(value + " a unique property was found but no existing value")
                logging.debug("setting " + str(ref_object) + " " + str(property) + " to " + str(value))
                setattr(ref_object, property, value)
                ref_object.put()
              else:
                logging.info(str(object) + " has no " + str(property))
          else:
            logging.info(str(entity) + " has no " + str(object))
        else:
          pass
      else:
        logging.info('key was None')


  @staticmethod
  def get_post_data(request):
    logging.debug(request.POST)
    key_list = request.arguments()
    for key in key_list:
      try:
        if not key in request.POST:
          if request.get(key):
            request.POST.add(key,request.get(key))
          else:
            logging.debug(key + ' doesnt have any post value attached, not adding to post data')
        else:
          logging.debug(key + ' already in the post data, ignoring')
      except Exception as e:
        logging.error('Error while adding post data ')
        logging.exception(e)
    return request.POST

  @staticmethod
  def make_query_string(current, add={}, delete=[]):
    new = {}
    for key in current:
      if not key in delete:
        new[key] = current[key]
    new.update(add)
    if not new:
      return ''
    return '?' + urllib.urlencode(new)

  def on_form_valid(self):
    pass

  @authenticate_user
  @controller
  def post(self, action=None, _redirect=True):
    '''
      post data is of them form key=value in the url query_string or post form
      /businesses/pos_device?key=afdsaf&config=abscd
        ==> changes config property of pos_device with device key
    '''
    from config import WombatConfig
    if not self.check_user_auth_token():
      return False
    try:
      active_path = self.request.path
      logging.info("Posting from main request handler from " + active_path + " with query " + self.request.query_string)
      if active_path.startswith("/businesses/pos_device"):
        logging.warn("changing path of: " + active_path)
        active_path = "/users" + active_path
  #   must consider receipt feedback login in get
      if active_path == self.user_login_path:
        logging.info('post handling a login for email = ' + self.request.get('email'))
        form = LoginForm(self.request.POST)
          #redirect to the session vaue
        session = self.session
        query = User.all().filter('email =', self.request.get('email').lower())
        user = query.get()
        if user and user.check_password(self.request.get('password')):
          logging.info('login successful ')
          session['user_key'] = str(user.key())
          logging.debug('session: ' + str(self.session))
          user.last_login = datetime.datetime.now()
          user.put()
          device_key = self.request.get('device_key')
          logging.debug('device_key = ' + str(device_key))
          app_user = users.get_current_user()
          real_account = user.get_active_account()
          resolved_referrer_url = WombatConfig.after_login_path
          if device_key:
            from users.businesses.models import PosDevice
            self.redirect(PosDevice.class_url() + '?device_key=' + device_key)
            return
          elif user.type == 'datahub':
            logging.info('Datahub user, will redirect to the Datahub')
            resolved_referrer_url = '/datahub'
          elif 'login_referrer' in session and session['login_referrer'] and not 'ajax=true' in session['login_referrer'].lower():
            referrer = session['login_referrer'][:]
            try:
              session['login_referrer'] = ''
              del session['login_referrer']
            except Exception as e:
              logging.warn('Cannot clear session referrer')
              logging.exception(e)
            resolved_referrer_url = str(referrer)
          elif user.type == 'datahub-write-only':
            logging.info('Datahub wo user, will redirect to the Datahub')
            resolved_referrer_url = '/datahub#/customer'
          elif user.uses_autogenerated_password:
            resolved_referrer_url = user.uri
          elif user.type == 'datahub-till':
            logging.info('Datahub toill user, will redirect to the Datahub')
            resolved_referrer_url = '/datahub'
          else:
            logging.info('no referrer found, will redirect home')
            resolved_referrer_url = WombatConfig.after_login_path
          if real_account and real_account.is_default() and not (app_user and users.is_current_user_admin()):
            logging.info('redirecting to google login')
            self.redirect(users.create_login_url(resolved_referrer_url))
          else:
            logging.info('redirecting to resolved referrer url')
            self.redirect(resolved_referrer_url)
          return
        else:
          logging.info('login not successful ')
          if not user:
            logging.info('user email not found')
          else:
            logging.info('check password failed')
          form_errors = {}
          form_errors['email'] = ["Either the email address or password was incorrect."]
          self.template_values.update({
                                  'form' : form,
                                  'form_errors': form_errors,
                                  'form_action' : active_path,
                                  'forgotten_password_url': 'ulogin.html'+self.make_query_string(self.request.GET, {'action': 'send_password', 'email': self.request.get('email')})
                                 })

          template = Settings.template_environment.get_template('ulogin.html')
          self.response.out.write(template.render(self.template_values))
          return
      action = self.request.get('action')
      if action:
        logging.info('Handling action ' + action)
        entity = db.get(Wombat.yRKey(self.request.get('key')))
        if not self.active_account() or not entity.has_scope(self.active_account()) and (not self.active_account() or not self.active_account().is_default()):
          logging.info('Privileges not sufficient to run an action on %s' % repr(entity))
          self.error(403)
          return

        if action == 'delete':
          hide_with_children(self.request.get('key'), True)
        elif action == 'restore':
          hide_with_children(self.request.get('key'), False)
        elif action == 'clone':
          entity = db.get(self.request.get('key'))
          clone = entity.get_clone()
          clone.add_scope(self.active_account())
          clone.refresh_scope(True)

          if hasattr(clone, 'name'):
            try:
              if not clone.name:
                clone.name = clone.title
              clone.name += ' - copy'
              #if self.current_user:
              #  clone.name += '(%s)' % (self.current_user.get_local_time(datetime.datetime.now()))
              #else:
              #  clone.name += '(%s)' % (datetime.datetime.now())
            except Exception as e:
              logging.exception(e)
          clone.put()
          self.redirect(clone.uri)
          return
        else:
          logging.debug('External action')
          if not action in entity.get_actions():
            self.error(404)
            return
          entity.get_actions()[action]['class'](self.request, self.response, entity, self).post()
        return
      set_default_request_template_values(self)
      #post_data = WombatRequestHandler.get_post_data(self.request)
      params = NestedMultiDict(self.request._str_POST, self.request._str_GET)
      params = UnicodeMultiDict(params, encoding=self.request.charset,
                                        errors=self.request.unicode_errors,
                                        decode_keys=self.request.decode_param_names)
      post_data = params
      self.template_values = WombatRequestHandler.put_query_models_into_template_values(active_path,self.request.query_string, self.template_values,post_data)
      self.template_values = self.get_form_from_path(active_path,self.request.query_string, self.template_values,post_data)
      #also assume here that if all postable objects have a form associated.
      logging.debug("set all template values")
      if 'form' in self.template_values:
        logging.debug('about to validate form.')
        if self.request.get('key'):
          try:
            entity = db.get(Wombat.yRKey(self.request.get('key')))
          except:
            entity = None
          if not entity:
            try:
              model_name = WombatRequestHandler.get_full_class_name_from_path(self.request.path)
              cur_class = _get_class(model_name)
              entity = cur_class.find(key=self.request.get('key'))
              if not entity:
                self.error(404)
            except:
              self.error(404)
          if (entity.__class__.__name__ != 'PosDevice' or self.request.get('business_location')) and (not self.active_account() or not self.active_account().is_default()):
            if not self.active_account() or not entity.has_scope(self.active_account()) or not entity.__class__.scope:
              logging.info('Access denied')
              self.error(403)
              return
        form = self.template_values['form']
        logging.debug("form data = " + str(form.data))
        form_valid = True
        form_exception = None
        form_errors = None
        if form.validate():
          request_account = False
          try:
            self.on_form_valid()
            logging.debug(str(form.__class__.__name__) + ' posted with valid data')
            if 'instance_name' in self.template_values:
              logging.info("creating entity from existing entity")
              entity = self.template_values[self.template_values['instance_name']]
              form.populate_obj(entity)
            else:
              model_name = WombatRequestHandler.get_full_class_name_from_path(active_path)
              model_class = _get_class(model_name)
              if model_class == Account:
                request_account = True
              #logging.info("form data = " + str(form.data))
              key_name = self.request.get(model_class.__name__+'.key_name')
              logging.debug(key_name)
              logging.debug(model_class.__name__+':key_name')
              entity = form_model(form,model_class,key_name=key_name)

            form_data = form.data
            for key in form_data.keys():
              if hasattr(entity.__class__, key):
                property = getattr(entity.__class__, key)
                if isinstance(property.required, Requirer):
                  try:
                    property.required.validate(property, key, form_data[key], entity)
                  except db.BadValueError, e:
                    form_valid = False
                    form.errors[key] = e

            if form_valid:
              if self.request.get('__wombat_add_as') and self.active_account() and self.active_account().is_default():
                logging.info('Active scope '+str(self.active_account()))
                entity.add_scope(db.get(self.request.get('__wombat_add_as')))
              elif self.active_account():
                logging.info('Active scope '+str(self.active_account()))
                entity.add_scope(self.active_account())
              logging.debug('about to set complex parameters')
              #args = self.request.arguments()
              #WombatRequestHandler.set_complex_form_arguments(args,self.request, entity)
              attributes = Wombat.props(entity)
              for attribute_name in attributes:
                value = getattr(entity, attribute_name)
                if 'colour' in attribute_name and value:
                  if re.match('[0-9a-zA-Z]{6}', value):
                    setattr(entity, attribute_name, '#' + value)
              entity.refresh_scope(True)
              entity.clean_scope()
              entity.put()
              self.response.headers.add_header('x-yreceipts-entity-key', str(entity.key()))
              self.session['messages'].append('The entity has been saved.')
              class_name = entity.__class__.__name__
              if entity.__class__ == Account:
                # delete cache for account list when a new account is added
                real = self.real_account()
                if real:
                  memcache_path = '/wombat/%s/available_accounts' % real.key()
                  memcache.delete(memcache_path)
                  logging.info('Deleted account cache at %s' % memcache_path)
              if not 'instance_name' in self.template_values and class_name != "ReceiptFeedback":
                message = "entity was created %s" % repr(entity)
                logging.info(message)
                send_mail(sender="customer.service@yreceipts.com",
                  to="teamyr@yreceipts.com",
                  subject=message,
                  body="")
              hook_method = 'put' if 'instance_name' in self.template_values else 'post'
              entity.queue_hooks(hook_method)
              if request_account:
                logging.info('requesting newly created account')
                self.request_account(entity.key())
              logging.info("entity saved ")
              if '.' in os.environ['HTTP_HOST']:
                logging.debug('checking if entity has insert_into_MySQL')
                if hasattr(entity, 'insert_into_MySQL'):
                  logging.info('queueing insert_into_MySQL')
                  entity.queue_method_calls('insert_into_MySQL')
                entity.queue_method_calls('make_search_index')
              self.posted_entity = entity
              referrer = self.request.get('referrer')
              referrer = referrer.replace('{{__key__}}', str(entity.key()))
              if referrer:
                logging.info("Redirecting to referrer " + referrer)
                self.redirect(referrer)
              elif _redirect:
                logging.info("Redirecting to default " + entity.href())
                self.redirect(entity.href())
          except Exception as e:
            form_valid = False
            logging.error(str(form.__class__.__name__) + ' could not be processed, although posted with valid data')
            logging.exception(e)
            self.response.headers.add_header('x-yreceipts-form-exception', str(e))
            form_exception = e
        else:
          form_valid = False
        if not form_valid:
          if form.errors:
            self.template_values['form_errors'] = form.errors
            self.response.headers.add_header('x-yreceipts-form-errors', str(';'.join('%s:%s' % (key, ','.join(values)) for key, values in form.errors.iteritems())))
          if form_exception:
            self.template_values['form_exception'] = form_exception
          logging.debug(str(form.__class__.__name__) + ' posted with invalid data ' + str(form.errors))
          self.template_values = self.template_values = self.get_form_from_path(active_path,self.request.query_string, self.template_values, post_data, True)
          template = self.get_template_from_url(active_path)
          self.response.out.write(template.render(self.template_values))
          return
      else:#form not in template values.
        if 'instance_name' in self.template_values:
          object = self.template_values[self.template_values['instance_name']]
          changed = False
          for argument in self.request.arguments():
            if hasattr(object, argument) and argument != 'key':
              changed = True
              logging.debug("setting " + argument + " to " + self.request.get(argument))
              setattr(object, argument, self.request.get(argument))
              object.put
          if changed:
            object.put()
          #propnames = [name for (name, value) in inspect.getmembers(object, isprop)]
        else:
          logging.warn("no valid form or property found for " + str(self.request.POST))
      return None
    except Exception404:
      self.error(404)

      #new object


from google.appengine.api import apiproxy_stub_map
from google.appengine.api.apiproxy_stub_map import APIProxyStubMap

class TimeoutAPIStub( object ):
    def __init__( self, service, deadline = 20 ):
        self.service = service
        self.deadline = deadline

    def CreateRPC( self ):
        rpc = apiproxy_stub_map.CreateRPC( self.service )
        rpc.deadline = self.deadline
        return rpc

def create_MakeSyncCall( service, deadline = 20 ):
    apsm = APIProxyStubMap()
    apsm.RegisterStub( service, TimeoutAPIStub( service, deadline ) )
    return apsm.MakeSyncCall


def send_mail_amazon(sender, to, subject, body, **kwargs):
    logging.info('About to send an email through Amazon SES from "%s"' % sender)
    from email.MIMEBase import MIMEBase
    from email.MIMEText import MIMEText
    from email import Encoders
    from email.mime.image import MIMEImage
    from email.mime.multipart import MIMEMultipart
    from email.Utils import COMMASPACE, formatdate
    import smtplib
    import boto
    import mimetypes
    # Import smtplib for the actual sending function
    # Create the container (outer) email message.
    if isinstance(to, basestring):
      to = [to]
    bcc = []
    if 'bcc' in kwargs and kwargs['bcc']:
      if isinstance(kwargs['bcc'], basestring):
        bcc = [kwargs['bcc']]
      else:
        bcc = kwargs['bcc']
    cc = []
    if 'cc' in kwargs and kwargs['cc']:
      if isinstance(kwargs['cc'], basestring):
        cc = [kwargs['cc']]
      else:
        cc = kwargs['cc']
    msg = MIMEMultipart('mixed')
    msg.set_charset('utf-8')
    alternative = MIMEMultipart('alternative')
    alternative.set_charset('utf-8')
    # We should no longer need this, as we're tracking bounces
    # programmatically
    #msg['Return-Path'] = 'amazonsesbounces@yreceipts.com'  # bounces
    msg['Subject'] = subject
    msg['From'] = sender

    if 'reply_to' in kwargs:
      msg['Reply-To'] = kwargs['reply_to']
    msg['Date'] = formatdate(localtime=True)
    msg['To'] = COMMASPACE.join(to)
    if cc:
      msg['Cc'] = COMMASPACE.join(cc)
    if bcc:
      msg['Bcc'] = COMMASPACE.join(bcc)

    logging.info('Message headers %s ' % msg)

    part1 = MIMEText(body, 'plain', 'utf-8')
    alternative.attach(part1)
    if 'html' in kwargs:
      part2 = MIMEText(kwargs['html'], 'html', 'utf-8')
      alternative.attach(part2)
    msg.attach(alternative)

    if 'attachments' in kwargs:
      for att in kwargs['attachments']:
        if att[0].endswith('.pkpass'):
          mime_type = 'application/vnd.apple.pkpass'
        elif att[0].endswith('.json'):
          mime_type = 'application/json'
        else:
          (mime_type, encoding) = mimetypes.guess_type(att[0], strict=False)
        part = MIMEBase(*mime_type.replace('x-','').split('/'))
        part.set_payload( att[1] )
        part.add_header('Content-Disposition', 'attachment', filename=att[0])
        Encoders.encode_base64(part)
        msg.attach(part)

    access_key_id = aws_access_key_id
    secret_access_key = aws_secret_access_key
    region = 'us-east-1'

    if 'amazon_ses' in kwargs:
      ses_conf = kwargs['amazon_ses']
      if 'access_key_id' in ses_conf and 'secret_access_key' in ses_conf:
        if ses_conf['access_key_id'] and ses_conf['secret_access_key']:
          access_key_id = ses_conf['access_key_id']
          secret_access_key = ses_conf['secret_access_key']
          if 'region' in ses_conf and ses_conf['region']:
            region = ses_conf['region']

    logging.info('access_key_id = %s' % access_key_id)
    logging.info('region = %s' % region)
    if not boto.config.has_section('Boto'):
      boto.config.add_section('Boto')
    # Certificate validation does not work properly on App Engine yet
    boto.config.set('Boto', 'https_validate_certificates', 'False')
    conn = boto.ses.connect_to_region(region, aws_access_key_id=access_key_id,
        aws_secret_access_key=secret_access_key)
    recipients = []
    recipients.extend(to)
    recipients.extend(bcc)
    recipients.extend(cc)
    try:
      result = conn.send_raw_email(msg.as_string())
    except SESAddressNotVerifiedError:
      conn.verify_email_address(sender)
      logging.error('Email address not verified; sending a verification email to %s' % sender)
      raise
    except SESAddressBlacklistedError:
      if len(to) == 1:
        from receipts.models import EmailAddress
        email = EmailAddress.get_or_insert(to[0])
        email.blacklisted_on = datetime.datetime.now()
        email.put()
      raise
    else:
      try:
        response = result['SendRawEmailResponse']
        message = AmazonSESEmailMessage()
        message.request_id = response['ResponseMetadata']['RequestId']
        message.message_id = response['SendRawEmailResult']['MessageId']
        message.sender = sender
        if 'reply_to' in kwargs:
          message.reply_to = kwargs['reply_to']
        message.to = list(to)
        message.cc = list(cc)
        message.bcc = list(bcc)
        if 'Return-Path' in msg:
          message.return_path = msg['Return-Path']
        message.subject = subject
        message.put()
        return message
      except Exception as e:
        logging.critical('Could not save an Amazon SES email message record')
        logging.exception(e)
    #conn.send_raw_email(msg.as_string(), 'contactdick@gmail.com','contactdick@gmail.com')

def check_throttling(to_email, number):
    EmailThrottlingCountClass(email_address=to_email).put()
    # clean old
    db.delete(EmailThrottlingCountClass.all().filter('added_on < ', datetime.datetime.now() + datetime.timedelta(minutes=-5)))
    current_list = EmailThrottlingCountClass.all().filter('email_address = ', to_email).fetch(1000)
    cur_len = len(current_list)
    if cur_len > number:
        logging.fatal(str(cur_len) + ' emails sent in the last 5 minutes, should be throttled')
        return False
    return True

def send_mail(*args, **kwargs):
  # it needs to raise real exception; otherwise, the receipt handler doesn't know whether sending was successful
  result = None
  try:
    args = list(args)
    if len(args):
      args[0] = args[0].replace(',', ' ') # sender
    if len(args) > 2:
      to = args[1]
      if not to:
        raise ValidationError('a to address is required')
      if isinstance(to, basestring):
        to_list = to.split(',')
      else:
        to_list = to
      for to_email in to_list:
        if to_email:
          validate_email(to_email)
          logging.info('About to validate "%s"' % to_email)
          if not check_throttling(to_email.lower(), 500):
              logging.error('throttling check failed, not sending ')
              return
    if 'sender' in kwargs and kwargs['sender']:
      kwargs['sender'] = kwargs['sender'].replace(',', ' ')
    if not 'yreceipts-test' in os.environ['HTTP_HOST']:
      if Settings.RUN_MODE == Settings.PRODUCTION or Settings.RUN_MODE == Settings.STAGING or '.' in os.environ['HTTP_HOST'] or True:
        if 'use_amazon' in kwargs and kwargs['use_amazon']:
          logging.debug('using amazon mailer')
          logging.info('About to call send_mail_amazon')
          result = send_mail_amazon(*args, **kwargs)
          logging.info('Called send_mail_amazon')
        else:
          if not 'make_sync_call' in kwargs:
            kwargs['make_sync_call'] = create_MakeSyncCall('mail', 40)
          if 'use_amazon' in kwargs:
            del kwargs['use_amazon']
          if 'amazon_ses' in kwargs:
            del kwargs['amazon_ses']
          logging.info('About to call mail.send_mail')
          mail.send_mail(*args,**kwargs)
          logging.info('Called mail.send_mail')
      else:
       logging.warn('**Not Sending out real email')
    else:
      logging.warn('**Not Sending out real email')
      logging.warn("'yreceipts-test' in os.environ['HTTP_HOST'] = %s" % os.environ['HTTP_HOST'])
    logging.info(args)
  except Exception as e:
    logging.error("Mail send recorded an error")
    logging.exception(e)
    raise
  else:
    if len(args) >= 2:
      to = args[1]
      if not isinstance(to, basestring):
        try:
          to = list(to)[0]
        except (TypeError, IndexError) as e:
          logging.exception(e)
          to = None
      if to:
        try:
          from receipts.models import EmailAddress
          email = EmailAddress.get_or_insert(to)
          email.emailed_on = datetime.datetime.now()
          email.put()
        except Exception as e:
          logging.exception(e)
  try:
    if Settings.RUN_MODE == Settings.DEVELOPMENT or Settings.RUN_MODE == Settings.TESTING:
      last_mail_sent = LastMailSent.all().get()
      if not last_mail_sent:
        last_mail_sent = LastMailSent()
      mail_string = ""
      short_mail_string = ""
      for arg in args:
        try:
          if not isinstance(arg, basestring):
            arg = unicode(arg)
          mail_string += arg + "\n"
          if len(arg) > 100:
            short_mail_string += "(length=" + unicode(len(arg)) + ")" + arg[0:100] + "...\n"
          else:
           short_mail_string += arg + "\n"
        except Exception as e:
          logging.exception(e)
      for key in kwargs:
        try:
          arg = unicode(kwargs[key])
          mail_string += (key + ":" + arg + "\n")
          if len(arg) > 100:
            short_mail_string += key + "(length=" + unicode(len(arg)) + "):" + arg[0:100] + "...\n"
          else:
            short_mail_string += (key + ":" + arg + "\n")
        except Exception as e:
          logging.exception(e)
      for key in kwargs:
        try:
          setattr(last_mail_sent, key, db.Text(unicode(kwargs[key])))
        except Exception as e:
          logging.exception(e)
      last_mail_sent.text = mail_string
      last_mail_sent.short_text = short_mail_string
      strargs = []
      for val in args:
        try:
          strargs.append(db.Text(unicode(val)))
        except Exception as e:
          logging.exception(e)
      last_mail_sent.args = strargs
      last_mail_sent.put()
  except Exception as e:
    logging.info(e)
  return result

class LastMailSent(db.Expando):
  text = db.TextProperty()
  short_text = db.TextProperty()
  args = db.ListProperty(db.Text)


class URLCookie(db.Model):
  #from consumers.identification.models import BarCode,PartialCreditCard
  _key_values = None
  cookie_id = db.StringProperty()
  _saved_key_values = db.StringProperty()
  added_on = db.DateTimeProperty(auto_now_add=True)

  @staticmethod
  def get_url_cookie_from_cookie_id(cookie_id):
    cur_cookie = URLCookie.all().filter('cookie_id =',cookie_id).get()
    if cur_cookie:
      cur_cookie._key_values = eval(cur_cookie._saved_key_values)
    return cur_cookie

  def __init__(self,*args,**kwargs):
    db.Model.__init__(self,*args,**kwargs)
    if "_from_entity" in kwargs:
      if kwargs["_from_entity"]:
        return
    random.seed()
    url_c = "%16x" % random.getrandbits(128)
    query = GqlQuery( "Select __key__ from %s where cookie_id = :1" % self.__class__.__name__,url_c)
    stored_key = query.get()
    if stored_key:
      logging.info('url_cookie %s is already in use, generating another' % url_c)
      url_c = "%16x2" % random.getrandbits(128)
    self.cookie_id = url_c
    if self._saved_key_values:
      self._key_values = eval(self._saved_key_values)
    else:
      self._key_values = {}


  def put(self):
    self._saved_key_values = repr(self._key_values)
    db.Model.put(self)


  def get_key_values(self):
    return self._key_values

  def set_key_values(self,kv):
    self._key_values = kv


  key_values = property(get_key_values,set_key_values)

class AccountRequestHandler(WombatDefaultRequestHandler):

  def get(self):
    pass

  def post(self):
    pass

class WombatForm(djangoforms.ModelForm):


  def __init__(self, *args, **kwargs):
    super(WombatForm, self).__init__(*args, **kwargs)
    #now reduce the query set to only have related models
#    for field_name in self.fields:
#      #prop_val = getattr(self, p)
#      field_model = self.fields[field_name]
#      if isinstance(field_model,djangoforms.ModelChoiceField):
#        root = Wombat.get_root_node(self.instance)
#        if root:
#          self.fields[field_name].query.ancestor(root)

class LoginForm(djangoforms.ModelForm):

    email = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput(render_value=False))


